#include "http-etag-combiner.h"

#include <assert.h>

static const size_t kDictCharCount = 16;

static const std::string kDefaultDict("0123456789ABCDEF");

static bool contains(const std::string &str, char c) {
    for (char ch : str) {
        if (ch == c) {
            return true;
        }
    }
    return false;
}

static char findCharNotInStr(const std::string &str) {
    assert(kDefaultDict.length() == kDictCharCount);
    for (char c : kDefaultDict) {
        if (!contains(str, c)) {
            return c;
        }
    }
    assert(false); // never reach here
    return 0;
}

static std::string removeDupChar(const std::string_view &dict) {
    std::string result;
    for (char c : dict) {
        if (!contains(result, c)) {
            result.push_back(c);
        }
    }
    return result;
}

static std::string normalizeDict(const std::string_view &dict) {
    std::string result = removeDupChar(dict);
    if (result.length() >= kDictCharCount) {
        return std::string(dict.substr(0, kDictCharCount));
    }
    while (result.length() < kDictCharCount) {
        result.push_back(findCharNotInStr(result));
    }
    return result;
}

HttpEtagCombiner::HttpEtagCombiner(const std::string_view &dict)
    : dict_(normalizeDict(dict)) {
}

void HttpEtagCombiner::combine(const std::string_view &str) {
    for (char c : str) {
        binary_.push_back(static_cast<unsigned char>(c));
    }
}

std::string HttpEtagCombiner::result() {
    std::string result;
    for (unsigned char b : binary_) {
        int i1 = (b >> 4) & 0xF;
        int i2 = b & 0xF;
        result.push_back(dict_[i1]);
        result.push_back(dict_[i2]);
    }
    return result;
}

